//+------------------------------------------------------------------+
//|																			Vector.h	|
//| Lightweight (fully inline) templated constant size storage class.|
//| Includes the usual scalar and vector operators.						|
//| More complicated calculations can be implemented with				|
//| the 'for_all' function and a lambda expression.						|
//| This allows the compiler to generate very efficient code.			|
//+------------------------------------------------------------------+
#pragma once



template<class T, size_t N>

//+==================================================================+
struct Vector
{
//+------------------------------------------------------------------+
//	member data array
	T data[N];

//+------------------------------------------------------------------+
//	static constant size - doesn't work reliably!?
//	static const size_t	SizeBytes	= N * sizeof(T);
	static const size_t	Size			= N;

//+------------------------------------------------------------------+
//	constructors
	Vector()							{						}
	Vector(const T      &init)	{	*this = init;	}
	Vector(const Vector &init)	{	*this = init;	}

//+------------------------------------------------------------------+
//	scalar and copy assignment operator
	Vector<T,N>& operator = (const Vector<T,N> &y);
	Vector<T,N>& operator = (const T &y);

//+------------------------------------------------------------------+
//	element access
//	const	T&	operator[]	(size_t i)	const		{	return data[i];	}
//			T&	operator[]	(size_t i)				{	return data[i];	}
	const	T&	get			(size_t i)	const		{	return data[i];	}
			T&	get			(size_t i)				{	return data[i];	}

//+------------------------------------------------------------------+
//	pointer conversion
	operator	const	T*		()				const		{	return data;		}
	operator			T*		()							{	return data;		}
	operator	const	void*	()				const		{	return data;		}
	operator			void*	()							{	return data;		}
				const	T*		begin()		const		{	return data;		}
				const	T*		end()			const		{	return data+N;		}

//+------------------------------------------------------------------+
//	call user defined functor or lambda function with all elements.
// For example squaring each element of a vector in C++0x:
//	Vector<double,1024> v(2.0);
//	v.for_all([&](double &a) { a *= a; });
	template<class F>	const	Vector<T,N>& for_all(F function) const;
	template<class F>			Vector<T,N>& for_all(F function);
	template<class F>			Vector<T,N>& for_all_unrolled(F function);



//+------------------------------------------------------------------+
	T				dot(const Vector<T,N>&)	const;
	T				normSquared()				const;
	T				norm()						const;
	Vector<T,N>&normalize();

};




///////////////////////////////////////////////////////////////////////////////
//	assignment operators
///////////////////////////////////////////////////////////////////////////////


//+----------------------------------------------------------------------------
//	vector assignment
template<class T, size_t N>
inline Vector<T,N>& Vector<T,N>::operator = (const Vector<T,N> &y)
{
	T			*dst = data,
				*lim = dst+N;
	const	T	*src = y;

	while(dst < lim)
		*dst++ = *src++;

	return *this;
}

//+----------------------------------------------------------------------------
//	scalar assignment
template<class T, size_t N>
inline Vector<T,N>& Vector<T,N>::operator = (const T &y)
{
	T	*dst = data,
		*lim = dst+N;

	while(dst < lim)
		*dst++ = y;

	return *this;
}

///////////////////////////////////////////////////////////////////////////////
//	arithmetic operators
///////////////////////////////////////////////////////////////////////////////


//+----------------------------------------------------------------------------
//	destructive vector operations
#define IMPLEMENT_VECTOR_OPERATOR(op)														\
																										\
	template<class T, size_t N>																\
	inline Vector<T,N>& operator op (Vector<T,N> &a, const Vector<T,N> &b)		\
	{																									\
		T			*dst = a,																		\
					*lim = dst+N;																	\
		const	T	*src = b;																		\
																										\
		while(dst < lim)																			\
			*dst++ op *src++;																		\
																										\
		return a;																					\
	}

//+----------------------------------------------------------------------------
//	destructive scalar operations
#define IMPLEMENT_SCALAR_OPERATOR(op)														\
																										\
	template<class T, size_t N>																\
	inline Vector<T,N>& operator op (Vector<T,N> &a, const T &b)					\
	{																									\
		T			*dst = a,																		\
					*lim = dst+N;																	\
																										\
		while(dst < lim)																			\
			*dst++ op b;																			\
																										\
		return a;																					\
	}


//+----------------------------------------------------------------------------
//	return by value vector operations
#define IMPLEMENT_VECTOR_OPERATOR_2(op)													\
																										\
	template<class T, size_t N>																\
	inline Vector<T,N> operator op (const Vector<T,N> &a, const Vector<T,N> &b)\
	{																									\
		Vector<T,N> result;																		\
																										\
		for(size_t n = 0; n < N; n++)															\
			result[n] = a[n] op b[n];															\
																										\
		return result;																				\
	}

//+----------------------------------------------------------------------------
//	return by value scalar operations
#define IMPLEMENT_SCALAR_OPERATOR_2(op)													\
																										\
	template<class T, size_t N>																\
	inline Vector<T,N> operator op (const Vector<T,N> &a, const T &b)				\
	{																									\
		Vector<T,N> result;																		\
																										\
		for(size_t n = 0; n < N; n++)															\
			result[n] = a[n] op b;																\
																										\
		return result;																				\
	}

IMPLEMENT_VECTOR_OPERATOR(+=)
IMPLEMENT_VECTOR_OPERATOR(-=)
IMPLEMENT_VECTOR_OPERATOR(*=)
IMPLEMENT_VECTOR_OPERATOR(/=)

IMPLEMENT_SCALAR_OPERATOR(+=)
IMPLEMENT_SCALAR_OPERATOR(-=)
IMPLEMENT_SCALAR_OPERATOR(*=)
IMPLEMENT_SCALAR_OPERATOR(/=)

IMPLEMENT_VECTOR_OPERATOR_2(+)
IMPLEMENT_VECTOR_OPERATOR_2(-)
IMPLEMENT_VECTOR_OPERATOR_2(*)
IMPLEMENT_VECTOR_OPERATOR_2(/)

IMPLEMENT_SCALAR_OPERATOR_2(+)
IMPLEMENT_SCALAR_OPERATOR_2(-)
IMPLEMENT_SCALAR_OPERATOR_2(*)
IMPLEMENT_SCALAR_OPERATOR_2(/)



///////////////////////////////////////////////////////////////////////////////

//+----------------------------------------------------------------------------
//	call user defined function with all elements
template<class T, size_t N>
template<class F>
__forceinline Vector<T,N>& Vector<T,N>::for_all(F f)
{
	T	*dst	= data,
		*lim	= dst+N;

	while(dst < lim)
		f(*dst++);

	return *this;
}

//+----------------------------------------------------------------------------
template<class T, size_t N>
template<class F>
__forceinline const Vector<T,N>& Vector<T,N>::for_all(F f) const
{
	const T	*dst	= data,
				*lim	= dst+N;

	while(dst < lim)
		f(*dst++);

	return *this;
}

//+----------------------------------------------------------------------------
//	call user defined function with all elements
template<class T, size_t N>
template<class F>
__forceinline Vector<T,N>& Vector<T,N>::for_all_unrolled(F f)
{
	T	*dst	= data,
		*lim	= dst+N;

	while(dst < lim)
	{
		f(*dst++);
		f(*dst++);
		f(*dst++);
		f(*dst++);
	}

	return *this;
}



///////////////////////////////////////////////////////////////////////////////

//+----------------------------------------------------------------------------
//	dot product
template<class T, size_t N>
__forceinline T Vector<T,N>::dot(const Vector<T,N> &b) const
{
	T res = 0;

	for(size_t n = 0; n < N; n++)
		res += data[n] * b[n];

	return res;
}


//+----------------------------------------------------------------------------
template<class T, size_t N>
__forceinline T Vector<T,N>::normSquared() const
{
	T res = 0;

	for(size_t n = 0; n < N; n++)
		res += data[n] * data[n];

	return res;
}

//+----------------------------------------------------------------------------
template<class T, size_t N>
__forceinline T Vector<T,N>::norm() const
{
	return sqrt(normSquared());
}

//+----------------------------------------------------------------------------
template<class T, size_t N>
__forceinline Vector<T,N>& Vector<T,N>::normalize()
{
	T length = norm();

//	if(f > std::numeric_limits<T>::epsilon())
	if(length)
	{
		for(size_t n = 0; n < N; n++)
			data[n] /= length;
	}

	return *this;
}



//+----------------------------------------------------------------------------
//	multiply accumulate: a += b * c
//	needs just 4 instructions (mov+mul+add+mov) and one register per operation.
//	unrolled = 4 registers.
template<class T, size_t N>
inline Vector<T,N>& MAD (Vector<T,N> &a, const Vector<T,N> &b, const Vector<T,N> &c)
{
	const	T	*src1	= b,
				*src2 = c;
//----
//	C++0x only:
//	a.for_all([&](T &x) { x += *src1++ * *src2++; });

	T	*dst	= a,
		*lim	= dst+N;

	for(_int i = 0; i < N; i++)
		dst[i] += src1[i] * src2[i];

	return a;

}



